home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / RANDOM.C < prev    next >
C/C++ Source or Header  |  1993-04-19  |  33KB  |  1,331 lines

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "estruct.h"
  8. #include "eproto.h"
  9. #include "edef.h"
  10. #include "elang.h"
  11.  
  12. /*
  13.  * Set fill column to n.
  14.  */
  15.  
  16. PASCAL NEAR setfillcol(f, n)
  17.  
  18. int f, n;                /* prefix flag and argument */
  19.     {
  20.     fillcol = n;
  21.     mlwrite(TEXT59, n);
  22. /*        "[Fill column is %d]" */
  23.     return (TRUE);
  24.     }
  25.  
  26. /*
  27.  * Display the current position of the cursor, in origin 1 X-Y coordinates,
  28.  * the character that is under the cursor (in hex), and the fraction of the
  29.  * text that is before the cursor. The displayed column is not the current
  30.  * column, but the column that would be used on an infinite width display.
  31.  * Normally this is bound to "C-X =".
  32.  */
  33.  
  34. PASCAL NEAR showcpos(f, n)
  35.  
  36. int f, n;                /* prefix flag and argument */
  37.     {
  38.     register LINE    *lp;    /* current line */
  39.     register long    numchars;    /* # of chars in file */
  40.     register long    numlines;    /* # of lines in file */
  41.     register long    predchars;    /* # chars preceding point */
  42.     register long    predlines;    /* # lines preceding point */
  43.     register int    curchar;    /* character under cursor */
  44.     int ratio;
  45.     int col;
  46.     int savepos;        /* temp save for current offset */
  47.     int ecol;            /* column pos/end of current line */
  48.  
  49.     /* starting at the beginning of the buffer */
  50.     lp = lforw(curbp->b_linep);
  51.     curchar = '\r';
  52.  
  53.     /* start counting chars and lines */
  54.     numchars = 0;
  55.     numlines = 0L;
  56.     while (lp != curbp->b_linep)
  57.         {
  58.         /* if we are on the current line, record it */
  59.         if (lp == curwp->w_dotp)
  60.             {
  61.             predlines = numlines;
  62.             predchars = numchars + curwp->w_doto;
  63.             if ((curwp->w_doto) == lused(lp))
  64.                 curchar = '\r';
  65.             else
  66.                 curchar = lgetc(lp, curwp->w_doto);
  67.             }
  68.         /* on to the next line */
  69.         ++numlines;
  70.         numchars += lused(lp) + 1;
  71.         lp = lforw(lp);
  72.         }
  73.  
  74.     /* if at end of file, record it */
  75.     if (curwp->w_dotp == curbp->b_linep)
  76.         {
  77.         predlines = numlines;
  78.         predchars = numchars;
  79.         }
  80.  
  81.     /* Get real column and end-of-line column. */
  82.     col = getccol(FALSE);
  83.     savepos = curwp->w_doto;
  84.     curwp->w_doto = lused(curwp->w_dotp);
  85.     ecol = getccol(FALSE);
  86.     curwp->w_doto = savepos;
  87.  
  88.     ratio = 0;            /* Ratio before dot. */
  89.     if (numchars != 0)
  90.         ratio = (100L * predchars) / numchars;
  91.  
  92.     /* summarize and report the info */
  93. #if    DBCS
  94.     if (is2byte(ltext(curwp->w_dotp),
  95.         ltext(curwp->w_dotp) + curwp->w_doto)) {
  96.         mlwrite(TEXT220,
  97. /*        "Line %D/%D Col %d/%d Char %D/%D (%d%%) char = 0x%x%x" */
  98.             predlines+1, numlines+1, col, ecol,
  99.             predchars, numchars, ratio, (unsigned char)curchar,
  100.             (unsigned char)(lgetc(curwp->w_dotp, curwp->w_doto+1)));
  101.         return(TRUE);
  102.     }
  103. #endif
  104.     mlwrite(TEXT60,
  105. /*        "Line %D/%D Col %d/%d Char %D/%D (%d%%) char = 0x%x" */
  106.         predlines + 1, numlines + 1, col, ecol,
  107.         predchars, numchars, ratio, curchar);
  108.     return (TRUE);
  109.     }
  110.  
  111. long PASCAL NEAR getlinenum(bp, sline)    /* get the a line number */
  112.  
  113. BUFFER *bp;                /* buffer to get current line from */
  114. LINE *sline;            /* line to search for */
  115.     {
  116.     register LINE    *lp;    /* current line */
  117.     register long    numlines;    /* # of lines before point */
  118.  
  119.     /* starting at the beginning of the buffer */
  120.     lp = lforw(bp->b_linep);
  121.  
  122.     /* start counting lines */
  123.     numlines = 0L;
  124.     while (lp != bp->b_linep)
  125.         {
  126.         /* if we are on the current line, record it */
  127.         if (lp == sline)
  128.             break;
  129.         ++numlines;
  130.         lp = lforw(lp);
  131.         }
  132.  
  133.     /* and return the resulting count */
  134.     return (numlines + 1L);
  135.     }
  136.  
  137. /*
  138.  * Return current column.  Stop at first non-blank given TRUE argument.
  139.  */
  140.  
  141. PASCAL NEAR getccol(bflg)
  142. int bflg;
  143.  
  144. {
  145.     register int c, i, col;
  146.  
  147.     col = 0;
  148.     for (i = 0;  i < curwp->w_doto;  ++i) {
  149.         c = lgetc(curwp->w_dotp, i) & 0xFF;
  150.         if (c != ' ' && c != '\t' && bflg)
  151.             break;
  152.         if (c == '\t')
  153.             col += -(col % tabsize) + (tabsize - 1);
  154.         else if (c < 0x20 || c == 0x7F)
  155.             ++col;
  156.         ++col;
  157.     }
  158.     return(col);
  159. }
  160.  
  161. /*    findcol: Return display column in line at char position    */
  162.  
  163. int PASCAL NEAR findcol(lp, pos)
  164.  
  165. LINE * lp;                /* line to scan */
  166. int pos;                /* character offset */
  167.     {
  168.     register int c, i, col;
  169.  
  170.     col = 0;
  171.     for (i = 0;  i < pos;  ++i)
  172.         {
  173.         c = lgetc(lp, i);
  174.         if (c == '\t')
  175.             col += -(col % tabsize) + (tabsize - 1);
  176.         else if (c < 0x20 || c == 0x7F)
  177.             ++col;
  178.         ++col;
  179.         }
  180.     return (col);
  181.     }
  182.  
  183. /*
  184.  * Set current column.
  185.  */
  186.  
  187. PASCAL NEAR setccol(pos)
  188.  
  189. int pos;                /* position to set cursor */
  190.     {
  191.     register int c;        /* character being scanned */
  192.     register int i;        /* index into current line */
  193.     register int col;    /* current cursor column   */
  194.     register int llen;    /* length of line in bytes */
  195.  
  196.     col = 0;
  197.     llen = lused(curwp->w_dotp);
  198.  
  199.     /* scan the line until we are at or past the target column */
  200.     for (i = 0;  i < llen;  ++i)
  201.         {
  202.         /* upon reaching the target, drop out */
  203.         if (col >= pos)
  204.             break;
  205.  
  206.         /* advance one character */
  207.         c = lgetc(curwp->w_dotp, i);
  208.         if (c == '\t')
  209.             col += -(col % tabsize) + (tabsize - 1);
  210.         else if (c < 0x20 || c == 0x7F)
  211.             ++col;
  212.         ++col;
  213.         }
  214.  
  215.     /* set us at the new position */
  216.     curwp->w_doto = i;
  217.  
  218.     /* and tell weather we made it */
  219.     return (col >= pos);
  220.     }
  221.  
  222. /*
  223.  * Twiddle the two characters on either side of dot. If dot is at the end of
  224.  * the line twiddle the two characters before it. Return with an error if dot
  225.  * is at the beginning of line; it seems to be a bit pointless to make this
  226.  * work. This fixes up a very common typo with a single stroke. Normally bound
  227.  * to "C-T". This always works within a line, so "WFEDIT" is good enough.
  228.  */
  229.  
  230. PASCAL NEAR twiddle(f, n)
  231.  
  232. int f, n;                /* prefix flag and argument */
  233.     {
  234.     register LINE    *dotp;
  235.     register int    doto;
  236.     register int    cl;
  237.     register int    cr;
  238.  
  239.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  240.         return (rdonly());    /* we are in read only mode    */
  241.     dotp = curwp->w_dotp;
  242.     doto = curwp->w_doto;
  243.     if (doto == lused(dotp) && --doto < 0)
  244.         return (FALSE);
  245.     cr = lgetc(dotp, doto);
  246.     if (--doto < 0)
  247.         return (FALSE);
  248.     cl = lgetc(dotp, doto);
  249.     lputc(dotp, doto+0, cr);
  250.     lputc(dotp, doto+1, cl);
  251.     lchange(WFEDIT);
  252.     return (TRUE);
  253.     }
  254.  
  255. /*
  256.  * Quote the next character, and insert it into the buffer. All the characters
  257.  * are taken literally, including the newline, which does not then have
  258.  * its line splitting meaning. The character is always read, even if it is
  259.  * inserted 0 times, for regularity. Bound to "C-Q". If a mouse action or
  260.  * function key is pressed, its symbolic MicroEMACS name gets inserted!
  261.  */
  262.  
  263. PASCAL NEAR quote(f, n)
  264.  
  265. int f, n;                /* prefix flag and argument */
  266.     {
  267.     register int ec;    /* current extended key fetched */
  268.     register int c;        /* current ascii key fetched */
  269.     register int status;    /* return value to hold from linstr */
  270.     char key_name[10];    /* name of a keystroke for quoting */
  271.  
  272.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  273.         return (rdonly());    /* we are in read only mode    */
  274.     ec = getkey();
  275.  
  276.     /* fail this on a negative argument */
  277.     if (n < 0)
  278.         return (FALSE);
  279.  
  280.     /* nothing to insert . . . blow it off */
  281.     if (n == 0)
  282.         return (TRUE);
  283.  
  284.     /* if this is a mouse event or function key, put its name in */
  285.     if ((ec & MOUS) || (ec & SPEC))
  286.         {
  287.         cmdstr(ec, key_name);
  288.         while (n--)
  289.             {
  290.             status = linstr(key_name);
  291.             if (status != TRUE)
  292.                 return (status);
  293.             }
  294.         return (TRUE);
  295.         }
  296.  
  297.     /* otherwise, just insert the raw character */
  298.     c = ectoc(ec);
  299.     return (linsert(n, c));
  300.     }
  301.  
  302. /*
  303.  * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
  304.  * tab into file.  If given argument, n, of zero, change to hard tabs.
  305.  * If n > 1, simulate tab stop every n-characters using spaces. This has to be
  306.  * done in this slightly funny way because the tab (in ASCII) has been turned
  307.  * into "C-I" (in 10 bit code) already. Bound to "C-I".
  308.  */
  309.  
  310. PASCAL NEAR tab(f, n)
  311.  
  312. int f, n;                /* prefix flag and argument */
  313.     {
  314.     if (n < 0)
  315.         return (FALSE);
  316.     if (n == 0 || n > 1)
  317.         {
  318.         stabsize = n;
  319.         return (TRUE);
  320.         }
  321.     if (!stabsize)
  322.         return (linsert(1, '\t'));
  323.     return (linsert(stabsize - (getccol(FALSE) % stabsize), ' '));
  324.     }
  325.  
  326. PASCAL NEAR detab(f, n)     /* change tabs to spaces */
  327.  
  328. int f, n;                /* default flag and numeric repeat count */
  329.     {
  330.     register int inc;    /* increment to next line [sgn(n)] */
  331.  
  332.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  333.         return (rdonly());    /* we are in read only mode    */
  334.  
  335.     if (f == FALSE)
  336.         n = reglines();
  337.  
  338.     /* loop thru detabbing n lines */
  339.     inc = ((n > 0) ? 1 : -1);
  340.     while (n)
  341.         {
  342.         curwp->w_doto = 0;    /* start at the beginning */
  343.  
  344.         /* detab the entire current line */
  345.         while (curwp->w_doto < lused(curwp->w_dotp))
  346.             {
  347.             /* if we have a tab */
  348.             if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t')
  349.                 {
  350.                 ldelete(1L, FALSE);
  351. /*                insspace(TRUE, 8 - (curwp->w_doto & 7));*/
  352.                 insspace(TRUE, tabsize - (curwp->w_doto % tabsize));
  353.                 }
  354.             forwchar(FALSE, 1);
  355.             }
  356.  
  357.         /* advance/or back to the next line */
  358.         forwline(TRUE, inc);
  359.         n -= inc;
  360.         }
  361.     curwp->w_doto = 0;    /* to the begining of the line */
  362.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  363.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  364.     return (TRUE);
  365.     }
  366.  
  367.  
  368. PASCAL NEAR entab(f, n)     /* change spaces to tabs where posible */
  369.  
  370. int f, n;                /* default flag and numeric repeat count */
  371.     {
  372.     register int inc;    /* increment to next line [sgn(n)] */
  373.     register int fspace;    /* pointer to first space if in a run */
  374.     register int ccol;    /* current cursor column */
  375.     register char cchar;    /* current character */
  376.  
  377.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  378.         return (rdonly());    /* we are in read only mode    */
  379.  
  380.     if (f == FALSE)
  381.         n = reglines();
  382.  
  383.     /* loop thru entabbing n lines */
  384.     inc = ((n > 0) ? 1 : -1);
  385.     while (n)
  386.         {
  387.         /* entab the entire current line */
  388.  
  389.         ccol = curwp->w_doto = 0;    /* start at the beginning */
  390.         fspace = -1;
  391.  
  392.         while (curwp->w_doto < lused(curwp->w_dotp))
  393.             {
  394.             /* see if it is time to compress */
  395.             if ((fspace >= 0) && (nextab(fspace) <= ccol))
  396.                 if (ccol - fspace < 2)
  397.                     fspace = -1;
  398.                 else {
  399.                     backchar(TRUE, ccol - fspace);
  400.                     ldelete((long) (ccol - fspace), FALSE);
  401.                     linsert(1, '\t');
  402.                     fspace = -1;
  403.                     }
  404.  
  405.             /* get the current character */
  406.             cchar = lgetc(curwp->w_dotp, curwp->w_doto);
  407.  
  408.             switch (cchar)
  409.                 {
  410.             case '\t':    /* a tab...count em up (no break here)  */
  411.                 ldelete(1L, FALSE);
  412.                 insspace(TRUE, tabsize - (ccol % tabsize));
  413.  
  414.             case ' ':    /* a space...compress? */
  415.                 if (fspace == -1)
  416.                     fspace = ccol;
  417.                 break;
  418.  
  419.             default:    /* any other char...just count */
  420.                 fspace = -1;
  421.                 break;
  422.                 }
  423.             ccol++;
  424.             forwchar(FALSE, 1);
  425.             }
  426.  
  427.         /* advance/or back to the next line */
  428.         forwline(TRUE, inc);
  429.         n -= inc;
  430.         curwp->w_doto = 0;    /* start at the beginning */
  431.         }
  432.     curwp->w_doto = 0;    /* to the begining of the line */
  433.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  434.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  435.     return (TRUE);
  436.     }
  437.  
  438. /* trim:    trim trailing whitespace from the point to eol
  439.         with no arguments, it trims the current region
  440. */
  441.  
  442. PASCAL NEAR trim(f, n)
  443.  
  444. int f, n;                /* default flag and numeric repeat count */
  445.     {
  446.     register LINE *lp;    /* current line pointer */
  447.     register int offset;    /* original line offset position */
  448.     register int length;    /* current length */
  449.     register int inc;    /* increment to next line [sgn(n)] */
  450.  
  451.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  452.         return (rdonly());    /* we are in read only mode    */
  453.  
  454.     if (f == FALSE)
  455.         n = reglines();
  456.  
  457.     /* loop thru trimming n lines */
  458.     inc = ((n > 0) ? 1 : -1);
  459.     while (n)
  460.         {
  461.         lp = curwp->w_dotp;    /* find current line text */
  462.         offset = curwp->w_doto;    /* save original offset */
  463.         length = lused(lp);    /* find current length */
  464.  
  465.         /* trim the current line */
  466.         while (length > offset)
  467.             {
  468.             if (lgetc(lp, length-1) != ' ' &&
  469.                 lgetc(lp, length-1) != '\t')
  470.                 break;
  471.             length--;
  472.             }
  473.         lp->l_used = length;
  474.  
  475.         /* advance/or back to the next line */
  476.         forwline(TRUE, inc);
  477.         n -= inc;
  478.         }
  479.     lchange(WFEDIT);
  480.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  481.     return (TRUE);
  482.     }
  483.  
  484. /*
  485.  * Open up some blank space. The basic plan is to insert a bunch of newlines,
  486.  * and then back up over them. Everything is done by the subcommand
  487.  * procerssors. They even handle the looping. Normally this is bound to "C-O".
  488.  */
  489.  
  490. PASCAL NEAR openline(f, n)
  491.  
  492. int f, n;                /* prefix flag and argument */
  493.     {
  494.     register int    i;
  495.     register int    s;
  496.  
  497.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  498.         return (rdonly());    /* we are in read only mode    */
  499.     if (n < 0)
  500.         return (FALSE);
  501.     if (n == 0)
  502.         return (TRUE);
  503.     i = n;                /* Insert newlines.    */
  504.     do    {
  505.         s = lnewline();
  506.         }
  507.     while (s == TRUE && --i);
  508.     if (s == TRUE)        /* Then back up overtop */
  509.         s = backchar(f, n);    /* of them all.     */
  510.     return (s);
  511.     }
  512.  
  513. /*
  514.  * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
  515.  * indentation as specified.
  516.  */
  517.  
  518. PASCAL NEAR newline(f, n)
  519.  
  520. int f, n;                /* prefix flag and argument */
  521.     {
  522.     register int    s;
  523.  
  524.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  525.         return (rdonly());    /* we are in read only mode    */
  526.     if (n < 0)
  527.         return (FALSE);
  528.  
  529.     /* if we are in C mode and this is a default <NL> */
  530.     if (n == 1 && (curbp->b_mode & MDCMOD) &&
  531.         curwp->w_dotp != curbp->b_linep)
  532.         return (cinsert());
  533.  
  534.     /*
  535.      * If a newline was typed, fill column is defined, the argument is non-
  536.      * negative, wrap mode is enabled, and we are now past fill column,
  537.      * and we are not read-only, perform word wrap.
  538.      */
  539.     if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  540.         getccol(FALSE) > fillcol &&
  541.         (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  542.         execkey(&wraphook, FALSE, 1);
  543.  
  544.     /* insert some lines */
  545.     while (n--)
  546.         {
  547.         if ((s = lnewline()) != TRUE)
  548.             return (s);
  549.         }
  550.     return (TRUE);
  551.     }
  552.  
  553. PASCAL NEAR cinsert()    /* insert a newline and indentation for C */
  554.  
  555.     {
  556.     register char *cptr;    /* string pointer into text to copy */
  557.     register int i;        /* index into line to copy indent from */
  558.     register int llen;    /* length of line to copy indent from */
  559.     register int bracef;    /* was there a brace at the end of line? */
  560.     register LINE *lp;    /* current line pointer */
  561.     register int offset;
  562.     char ichar[NSTRING];    /* buffer to hold indent of last line */
  563.  
  564.     /* trim the whitespace before the point */
  565.     lp = curwp->w_dotp;
  566.     offset = curwp->w_doto;
  567.     while (offset > 0 &&
  568.         (lgetc(lp, offset - 1) == ' ' ||
  569.         lgetc(lp, offset - 1) == '\t'))
  570.         {
  571.         backdel(FALSE, 1);
  572.         offset--;
  573.         }
  574.  
  575.     /* check for a brace */
  576.     bracef = (offset > 0 && lgetc(lp, offset - 1) == '{');
  577.  
  578.     /* put in the newline */
  579.     if (lnewline() == FALSE)
  580.         return (FALSE);
  581.  
  582.     /* if the new line is not blank... don't indent it! */
  583.     lp = curwp->w_dotp;
  584.     if (lused(lp) != 0)
  585.         return (TRUE);
  586.  
  587.     /* hunt for the last non-blank line to get indentation from */
  588.     while (lused(lp) == 0 && lp != curbp->b_linep)
  589.         lp = lback(lp);
  590.  
  591.     /* grab a pointer to text to copy indentation from */
  592.     cptr = ltext(lp);
  593.     llen = lused(lp);
  594.  
  595.     /* save the indent of the last non blank line */
  596.     i = 0;
  597.     while ((i < llen) && (cptr[i] == ' ' || cptr[i] == '\t')
  598.         && (i < NSTRING - 1))
  599.         {
  600.         ichar[i] = cptr[i];
  601.         ++i;
  602.         }
  603.     ichar[i] = 0;        /* terminate it */
  604.  
  605.     /* insert this saved indentation */
  606.     linstr(ichar);
  607.  
  608.     /* and one more tab for a brace */
  609.     if (bracef)
  610.         tab(FALSE, 1);
  611.  
  612.     return (TRUE);
  613.     }
  614.  
  615. PASCAL NEAR insbrace(n, c)    /* insert a brace into the text here...we are in CMODE */
  616.  
  617. int n;                    /* repeat count */
  618. int c;                    /* brace to insert (always } for now) */
  619.     {
  620.     register int ch;    /* last character before input */
  621.     register int oc;    /* caractere oppose a c */
  622.     register int i, count;
  623.     register int target;    /* column brace should go after */
  624.     register LINE *oldlp;
  625.     register int  oldoff;
  626.  
  627.     /* if we aren't at the beginning of the line... */
  628.     if (curwp->w_doto != 0)
  629.  
  630.     /* scan to see if all space before this is white space */
  631.         for (i = curwp->w_doto - 1;  i >= 0;  --i)
  632.             {
  633.             ch = lgetc(curwp->w_dotp, i);
  634.             if (ch != ' ' && ch != '\t')
  635.                 return (linsert(n, c));
  636.             }
  637.  
  638.     /* chercher le caractere oppose correspondant */
  639.     switch (c)
  640.         {
  641.     case '}':
  642.         oc = '{';
  643.         break;
  644.     case ']':
  645.         oc = '[';
  646.         break;
  647.     case ')':
  648.         oc = '(';
  649.         break;
  650.     default:
  651.         return (FALSE);
  652.         }
  653.  
  654.     oldlp = curwp->w_dotp;
  655.     oldoff = curwp->w_doto;
  656.  
  657.     count = 1;
  658.     backchar(FALSE, 1);
  659.  
  660.     while (count > 0)
  661.         {
  662.         if (curwp->w_doto == lused(curwp->w_dotp))
  663.             ch = '\r';
  664.         else
  665.             ch = lgetc(curwp->w_dotp, curwp->w_doto);
  666.  
  667.         if (ch == c)
  668.             ++count;
  669.         if (ch == oc)
  670.             --count;
  671.  
  672.         backchar(FALSE, 1);
  673.         if (boundry(curwp->w_dotp, curwp->w_doto, REVERSE))
  674.             break;
  675.         }
  676.  
  677.     if (count != 0)
  678.         {                /* no match */
  679.         curwp->w_dotp = oldlp;
  680.         curwp->w_doto = oldoff;
  681.         return (linsert(n, c));
  682.         }
  683.  
  684.     curwp->w_doto = 0;    /* debut de ligne */
  685.     /* aller au debut de la ligne apres la tabulation */
  686.     while ((ch = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || ch == '\t')
  687.         forwchar(FALSE, 1);
  688.  
  689.     /* delete back first */
  690.     target = getccol(FALSE);    /* c'est l'indent que l'on doit avoir */
  691.     curwp->w_dotp = oldlp;
  692.     curwp->w_doto = oldoff;
  693.  
  694.     while (target != getccol(FALSE))
  695.         {
  696.         if (target < getccol(FALSE))    /* on doit detruire des caracteres */
  697.             while (getccol(FALSE) > target)
  698.                 backdel(FALSE, 1);
  699.         else {            /* on doit en inserer */
  700.             while (target - getccol(FALSE) >= tabsize)
  701.                 linsert(1, '\t');
  702.             linsert(target - getccol(FALSE), ' ');
  703.             }
  704.         }
  705.  
  706.     /* and insert the required brace(s) */
  707.     return (linsert(n, c));
  708.     }
  709.  
  710. PASCAL NEAR inspound()    /* insert a # into the text here...we are in CMODE */
  711.  
  712.     {
  713.     register int ch;    /* last character before input */
  714.     register int i;
  715.  
  716.     /* if we are at the beginning of the line, no go */
  717.     if (curwp->w_doto == 0)
  718.         return (linsert(1, '#'));
  719.  
  720.     /* scan to see if all space before this is white space */
  721.     for (i = curwp->w_doto - 1;  i >= 0;  --i)
  722.         {
  723.         ch = lgetc(curwp->w_dotp, i);
  724.         if (ch != ' ' && ch != '\t')
  725.             return (linsert(1, '#'));
  726.         }
  727.  
  728.     /* delete back first */
  729.     while (getccol(FALSE) >= 1)
  730.         backdel(FALSE, 1);
  731.  
  732.     /* and insert the required pound */
  733.     return (linsert(1, '#'));
  734.     }
  735.  
  736. /*
  737.  * Delete blank lines around dot. What this command does depends if dot is
  738.  * sitting on a blank line. If dot is sitting on a blank line, this command
  739.  * deletes all the blank lines above and below the current line. If it is
  740.  * sitting on a non blank line then it deletes all of the blank lines after
  741.  * the line. Normally this command is bound to "C-X C-O". Any argument is
  742.  * ignored.
  743.  */
  744.  
  745. PASCAL NEAR deblank(f, n)
  746.  
  747. int f, n;                /* prefix flag and argument */
  748.     {
  749.     register LINE    *lp1;
  750.     register LINE    *lp2;
  751.     long nld;
  752.  
  753.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  754.         return (rdonly());    /* we are in read only mode    */
  755.     lp1 = curwp->w_dotp;
  756.     while (lused(lp1) == 0 && (lp2 = lback(lp1)) != curbp->b_linep)
  757.         lp1 = lp2;
  758.     lp2 = lp1;
  759.     nld = 0;
  760.     while ((lp2 = lforw(lp2)) != curbp->b_linep && lused(lp2) == 0)
  761.         ++nld;
  762.     if (nld == 0)
  763.         return (TRUE);
  764.     curwp->w_dotp = lforw(lp1);
  765.     curwp->w_doto = 0;
  766.     return (ldelete(nld, FALSE));
  767.     }
  768.  
  769. /*
  770.  * Insert a newline, then enough tabs and spaces to duplicate the indentation
  771.  * of the previous line. Tabs are every tabsize characters. Quite simple.
  772.  * Figure out the indentation of the current line. Insert a newline by calling
  773.  * the standard routine. Insert the indentation by inserting the right number
  774.  * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
  775.  * subcomands failed. Normally bound to "C-J".
  776.  */
  777.  
  778. PASCAL NEAR indent(f, n)
  779.  
  780. int f, n;                /* prefix flag and argument */
  781.     {
  782.     register int    nicol;
  783.     register int    c;
  784.     register int    i;
  785.  
  786.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  787.         return (rdonly());    /* we are in read only mode    */
  788.     if (n < 0)
  789.         return (FALSE);
  790.     while (n--)
  791.         {
  792.         nicol = 0;
  793.         for (i = 0;  i < lused(curwp->w_dotp);  ++i)
  794.             {
  795.             c = lgetc(curwp->w_dotp, i);
  796.             if (c != ' ' && c != '\t')
  797.                 break;
  798.             if (c == '\t')
  799.                 nicol += -(nicol % tabsize) + (tabsize - 1);
  800.             ++nicol;
  801.             }
  802.         if (lnewline() == FALSE
  803.             || ((i = nicol / tabsize) != 0 && linsert(i, '\t') == FALSE)
  804.             || ((i = nicol % tabsize) != 0 && linsert(i, ' ') == FALSE))
  805.             return (FALSE);
  806.         }
  807.     return (TRUE);
  808.     }
  809.  
  810. /*
  811.  * Delete forward. This is real easy, because the basic delete routine does
  812.  * all of the work. Watches for negative arguments, and does the right thing.
  813.  * If any argument is present, it kills rather than deletes, to prevent loss
  814.  * of text if typed with a big argument. Normally bound to "C-D".
  815.  */
  816.  
  817. PASCAL NEAR forwdel(f, n)
  818.  
  819. int f, n;                /* prefix flag and argument */
  820.     {
  821.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  822.         return (rdonly());    /* we are in read only mode    */
  823.     if (n < 0)
  824.         return (backdel(f, -n));
  825.     if (f != FALSE)
  826.         {                /* Really a kill.    */
  827.         if ((lastflag & CFKILL) == 0)
  828.             next_kill();
  829.         thisflag |= CFKILL;
  830.         }
  831.     return (ldelete((long) n, f));
  832.     }
  833.  
  834. /*
  835.  * Delete backwards. This is quite easy too, because it's all done with other
  836.  * functions. Just move the cursor back, and delete forwards. Like delete
  837.  * forward, this actually does a kill if presented with an argument. Bound to
  838.  * both "RUBOUT" and "C-H".
  839.  */
  840.  
  841. PASCAL NEAR backdel(f, n)
  842.  
  843. int f, n;                /* prefix flag and argument */
  844.     {
  845.     register int    s;
  846.  
  847.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  848.         return (rdonly());    /* we are in read only mode    */
  849.     if (n < 0)
  850.         return (forwdel(f, -n));
  851.     if (f != FALSE)
  852.         {                /* Really a kill.    */
  853.         if ((lastflag & CFKILL) == 0)
  854.             next_kill();
  855.         thisflag |= CFKILL;
  856.         }
  857.     if ((s = backchar(f, n)) == TRUE)
  858.         s = ldelete((long) n, f);
  859.     return (s);
  860.     }
  861.  
  862. /*
  863.  * Kill text. If called without an argument, it kills from dot to the end of
  864.  * the line, unless it is at the end of the line, when it kills the newline.
  865.  * If called with an argument of 0, it kills from the start of the line to dot.
  866.  * If called with a positive argument, it kills from dot forward over that
  867.  * number of newlines. If called with a negative argument it kills backwards
  868.  * that number of newlines. Normally bound to "C-K".
  869.  */
  870.  
  871. PASCAL NEAR killtext(f, n)
  872.  
  873. int f, n;                /* prefix flag and argument */
  874.     {
  875.     register LINE    *nextp;
  876.     long chunk;
  877.  
  878.     if (curbp->b_mode & MDVIEW)    /* don't allow this command if    */
  879.         return (rdonly());    /* we are in read only mode    */
  880.     if ((lastflag & CFKILL) == 0)    /* Clear kill buffer if */
  881.         next_kill();    /* last wasn't a kill.    */
  882.     thisflag |= CFKILL;
  883.  
  884.     if (f == FALSE)
  885.         {
  886.         chunk = lused(curwp->w_dotp) - curwp->w_doto;
  887.         if (chunk == 0)
  888.             chunk = 1;
  889.         }
  890.     else if (n == 0)
  891.         {
  892.         chunk = -curwp->w_doto;
  893.         }
  894.     else if (n > 0)
  895.         {
  896.         chunk = lused(curwp->w_dotp) - curwp->w_doto + 1;
  897.         nextp = lforw(curwp->w_dotp);
  898.         while (--n)
  899.             {
  900.             if (nextp == curbp->b_linep)
  901.                 return (FALSE);
  902.             chunk += lused(nextp) + 1;
  903.             nextp = lforw(nextp);
  904.             }
  905.         }
  906.     else if (n < 0)
  907.         {
  908.         chunk = -curwp->w_doto;
  909.         nextp = lback(curwp->w_dotp);
  910.         while (n++)
  911.             {
  912.             if (nextp == curbp->b_linep)
  913.                 return (FALSE);
  914.             chunk -= lused(nextp) + 1;
  915.             nextp = lback(nextp);
  916.             }
  917.         }
  918.     return (ldelete(chunk, TRUE));
  919.     }
  920.  
  921. PASCAL NEAR setmod(f, n)    /* prompt and set an editor mode */
  922.  
  923. int f, n;                /* default and argument */
  924.     {
  925.     return (adjustmode(TRUE, FALSE));
  926.     }
  927.  
  928. PASCAL NEAR delmode(f, n)    /* prompt and delete an editor mode */
  929.  
  930. int f, n;                /* default and argument */
  931.     {
  932.     return (adjustmode(FALSE, FALSE));
  933.     }
  934.  
  935. PASCAL NEAR setgmode(f, n)    /* prompt and set a global editor mode */
  936.  
  937. int f, n;                /* default and argument */
  938.     {
  939.     return (adjustmode(TRUE, TRUE));
  940.     }
  941.  
  942. PASCAL NEAR delgmode(f, n)    /* prompt and delete a global editor mode */
  943.  
  944. int f, n;                /* default and argument */
  945.     {
  946.     return (adjustmode(FALSE, TRUE));
  947.     }
  948.  
  949. PASCAL NEAR adjustmode(kind, global)    /* change the editor mode status */
  950.  
  951. int kind;                /* true = set,        false = delete */
  952. int global;                /* true = global flag,    false = current buffer flag */
  953.     {
  954.     register char *scan;    /* scanning pointer to convert prompt */
  955.     register int i;        /* loop index */
  956.     register int status;    /* error return on input */
  957. #if    COLOR
  958.     register int uflag;    /* was modename uppercase?    */
  959. #endif
  960.     char prompt[50];    /* string to prompt user with */
  961.     char cbuf[NPAT];    /* buffer to recieve mode name into */
  962.  
  963.     /* build the proper prompt string */
  964.     if (global)
  965.         strcpy(prompt, TEXT62);
  966. /*                  "Global mode to " */
  967.     else
  968.         strcpy(prompt, TEXT63);
  969. /*                  "Mode to " */
  970.  
  971.     if (kind == TRUE)
  972.         strcat(prompt, TEXT64);
  973. /*                   "add: " */
  974.     else
  975.         strcat(prompt, TEXT65);
  976. /*                   "delete: " */
  977.  
  978.     /* prompt the user and get an answer */
  979.  
  980.     status = mlreply(prompt, cbuf, NPAT - 1);
  981.     if (status != TRUE)
  982.         return (status);
  983.  
  984.     /* make it uppercase */
  985.  
  986.     scan = cbuf;
  987. #if    COLOR
  988.     uflag = (*scan >= 'A' && *scan <= 'Z');
  989. #endif
  990.     while (*scan)
  991.         uppercase((unsigned char *) scan++);
  992.  
  993.     /* test it first against the colors we know */
  994.     if ((i = lookup_color(cbuf)) != -1)
  995.         {
  996.  
  997. #if    COLOR
  998.         /* finding the match, we set the color */
  999.         if (global)
  1000.             {
  1001.             if (uflag)
  1002.                 gfcolor = i;
  1003.             else
  1004.                 gbcolor = i;
  1005. #if    WINDOW_TEXT & 0
  1006.             refresh_screen(first_screen);
  1007. #endif
  1008.             }
  1009.         else
  1010.             if (uflag)
  1011.                 curwp->w_fcolor = i;
  1012.             else
  1013.                 curwp->w_bcolor = i;
  1014.  
  1015.         curwp->w_flag |= WFCOLR;
  1016. #endif
  1017.         mlerase();
  1018.         return (TRUE);
  1019.         }
  1020.  
  1021.     /* test it against the modes we know */
  1022.  
  1023.     for (i = 0;  i < NUMMODES;  i++)
  1024.         {
  1025.         if (strcmp(cbuf, modename[i]) == 0)
  1026.             {
  1027.             /* finding a match, we process it */
  1028.             if (kind == TRUE)
  1029.                 if (global)
  1030.                     {
  1031.                     gmode |= (1 << i);
  1032.                     if ((1 << i) == MDOVER)
  1033.                         gmode &= ~MDREPL;
  1034.                     else if ((1 << i) == MDREPL)
  1035.                         gmode &= ~MDOVER;
  1036.                     }
  1037.                 else {
  1038.                     curbp->b_mode |= (1 << i);
  1039.                     if ((1 << i) == MDOVER)
  1040.                         curbp->b_mode &= ~MDREPL;
  1041.                     else if ((1 << i) == MDREPL)
  1042.                         curbp->b_mode &= ~MDOVER;
  1043.                     }
  1044.             else
  1045.                 if (global)
  1046.                     gmode &= ~(1 << i);
  1047.                 else
  1048.                     curbp->b_mode &= ~(1 << i);
  1049.             /* display new mode line */
  1050.             if (global == 0)
  1051.                 upmode();
  1052.             mlerase();    /* erase the junk */
  1053.             return (TRUE);
  1054.             }
  1055.         }
  1056.  
  1057.     mlwrite(TEXT66);
  1058. /*        "No such mode!" */
  1059.     return (FALSE);
  1060.     }
  1061.  
  1062. /*    This function simply clears the message line,
  1063.         mainly for macro usage            */
  1064.  
  1065. PASCAL NEAR clrmes(f, n)
  1066.  
  1067. int f, n;                /* arguments ignored */
  1068.     {
  1069.     mlforce("");
  1070.     return (TRUE);
  1071.     }
  1072.  
  1073. /*    This function writes a string on the message line
  1074.         mainly for macro usage            */
  1075.  
  1076. PASCAL NEAR writemsg(f, n)
  1077.  
  1078. int f, n;                /* arguments ignored */
  1079.     {
  1080.     register int status;
  1081.     char buf[NPAT];        /* buffer to recieve message into */
  1082.  
  1083.     if ((status = mlreply(TEXT67, buf, NPAT - 1)) != TRUE)
  1084. /*                  "Message to write: " */
  1085.         return (status);
  1086.  
  1087.     /* expand all '%' to "%%" so mlwrite won't expect arguments */
  1088.     makelit(buf);
  1089.  
  1090.     /* write the message out */
  1091.     mlforce(buf);
  1092.     return (TRUE);
  1093.     }
  1094.  
  1095. /*    the cursor is moved to a matching fence */
  1096.  
  1097. PASCAL NEAR getfence(f, n)
  1098.  
  1099. int f, n;                /* not used */
  1100.     {
  1101.     register LINE *oldlp;    /* original line pointer */
  1102.     register int oldoff;    /* and offset */
  1103.     register int sdir;    /* direction of search (1/-1) */
  1104.     register int count;    /* current fence level count */
  1105.     register char ch;    /* fence type to match against */
  1106.     register char ofence;    /* open fence */
  1107.     register char c;    /* current character in scan */
  1108.  
  1109.     /* save the original cursor position */
  1110.     oldlp = curwp->w_dotp;
  1111.     oldoff = curwp->w_doto;
  1112.  
  1113.     /* get the current character */
  1114.     if (oldoff == lused(oldlp))
  1115.         ch = '\r';
  1116.     else
  1117.         ch = lgetc(oldlp, oldoff);
  1118.  
  1119.     /* setup proper matching fence */
  1120.     switch (ch)
  1121.         {
  1122.     case '(':
  1123.         ofence = ')';
  1124.         sdir = FORWARD;
  1125.         break;
  1126.     case '{':
  1127.         ofence = '}';
  1128.         sdir = FORWARD;
  1129.         break;
  1130.     case '[':
  1131.         ofence = ']';
  1132.         sdir = FORWARD;
  1133.         break;
  1134.     case ')':
  1135.         ofence = '(';
  1136.         sdir = REVERSE;
  1137.         break;
  1138.     case '}':
  1139.         ofence = '{';
  1140.         sdir = REVERSE;
  1141.         break;
  1142.     case ']':
  1143.         ofence = '[';
  1144.         sdir = REVERSE;
  1145.         break;
  1146.     default:
  1147.         TTbeep();
  1148.         return (FALSE);
  1149.         }
  1150.  
  1151.     /* set up for scan */
  1152.     count = 1;
  1153.  
  1154.     /* scan until we find it, or reach the end of file */
  1155.     while (count > 0)
  1156.         {
  1157.         if (sdir == FORWARD)
  1158.             forwchar(FALSE, 1);
  1159.         else
  1160.             backchar(FALSE, 1);
  1161.  
  1162.         if (curwp->w_doto == lused(curwp->w_dotp))
  1163.             c = '\r';
  1164.         else
  1165.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1166.         if (c == ch)
  1167.             ++count;
  1168.         if (c == ofence)
  1169.             --count;
  1170.         if (boundry(curwp->w_dotp, curwp->w_doto, sdir))
  1171.             break;
  1172.         }
  1173.  
  1174.     /* if count is zero, we have a match, move the sucker */
  1175.     if (count == 0)
  1176.         {
  1177.         curwp->w_flag |= WFMOVE;
  1178.         return (TRUE);
  1179.         }
  1180.  
  1181.     /* restore the current position */
  1182.     curwp->w_dotp = oldlp;
  1183.     curwp->w_doto = oldoff;
  1184.     TTbeep();
  1185.     return (FALSE);
  1186.     }
  1187.  
  1188. /*    Close fences are matched against their partners, and if
  1189.     on screen the cursor briefly lights there        */
  1190.  
  1191. #if    PROTO
  1192. PASCAL NEAR fmatch(char ch)
  1193. #else
  1194. PASCAL NEAR fmatch(ch)
  1195.  
  1196. char ch;    /* fence type to match against */
  1197. #endif
  1198.  
  1199.     {
  1200.     register LINE *oldlp;    /* original line pointer */
  1201.     register int oldoff;    /* and offset */
  1202.     register LINE *toplp;    /* top line in current window */
  1203.     register int count;    /* current fence level count */
  1204.     register char opench;    /* open fence */
  1205.     register char c;    /* current character in scan */
  1206.     register int i;
  1207.  
  1208.     /* first get the display update out there */
  1209.     update(FALSE);
  1210.  
  1211.     /* save the original cursor position */
  1212.     oldlp = curwp->w_dotp;
  1213.     oldoff = curwp->w_doto;
  1214.  
  1215.     /* setup proper open fence for passed close fence */
  1216.     if (ch == ')')
  1217.         opench = '(';
  1218.     else if (ch == '}')
  1219.         opench = '{';
  1220.     else
  1221.         opench = '[';
  1222.  
  1223.     /* find the top line and set up for scan */
  1224.     toplp = lback(curwp->w_linep);
  1225.     count = 1;
  1226.     backchar(FALSE, 1);
  1227.  
  1228.     /* scan back until we find it, or reach past the top of the window */
  1229.     while (count > 0 && curwp->w_dotp != toplp)
  1230.         {
  1231.         backchar(FALSE, 1);
  1232.         if (curwp->w_doto == lused(curwp->w_dotp))
  1233.             c = '\r';
  1234.         else
  1235.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1236.         if (c == ch)
  1237.             ++count;
  1238.         if (c == opench)
  1239.             --count;
  1240.         if (curwp->w_dotp == lforw(curwp->w_bufp->b_linep) &&
  1241.             curwp->w_doto == 0)
  1242.             break;
  1243.         }
  1244.  
  1245.     /* if count is zero, we have a match, display the sucker */
  1246.     /* there is a real machine dependant timing problem here we have
  1247.        yet to solve......... */
  1248.     if (count == 0)
  1249.         {
  1250. #if    WINDOW_MSWIN
  1251.         update(FALSE);
  1252.         term.t_sleep (term.t_pause);
  1253. #else
  1254.         for (i = 0;  i < term.t_pause;  i++)
  1255.             update(FALSE);
  1256. #endif
  1257.         }
  1258.  
  1259.     /* restore the current position */
  1260.     curwp->w_dotp = oldlp;
  1261.     curwp->w_doto = oldoff;
  1262.     return (TRUE);
  1263.     }
  1264.  
  1265. PASCAL NEAR istring(f, n)    /* ask for and insert a string into the current
  1266.            buffer at the current point */
  1267.  
  1268. int f, n;                /* ignored arguments */
  1269.     {
  1270.     register int status;    /* status return code */
  1271.     char tstring[NPAT + 1];    /* string to add */
  1272.  
  1273.     /* ask for string to insert */
  1274.     status = nextarg(TEXT68, tstring, NPAT, sterm);
  1275. /*              "String to insert: " */
  1276.     if (status != TRUE)
  1277.         return (status);
  1278.  
  1279.     if (f == FALSE)
  1280.         n = 1;
  1281.  
  1282.     if (n < 0)
  1283.         n = -n;
  1284.  
  1285.     /* insert it */
  1286.     while (n-- && (status = linstr(tstring)))
  1287.         ;
  1288.     return (status);
  1289.     }
  1290.  
  1291. PASCAL NEAR ovstring(f, n)     /* ask for and overwite a string into the current
  1292.            buffer at the current point */
  1293.  
  1294. int f, n;                /* ignored arguments */
  1295.     {
  1296.     register int status;    /* status return code */
  1297.     char tstring[NPAT + 1];    /* string to add */
  1298.  
  1299.     /* ask for string to insert */
  1300.     status = nextarg(TEXT69, tstring, NPAT, sterm);
  1301. /*              "String to overwrite: " */
  1302.     if (status != TRUE)
  1303.         return (status);
  1304.  
  1305.     if (f == FALSE)
  1306.         n = 1;
  1307.  
  1308.     if (n < 0)
  1309.         n = -n;
  1310.  
  1311.     /* insert it */
  1312.     while (n-- && (status = lover(tstring)))
  1313.         ;
  1314.     return (status);
  1315.     }
  1316.  
  1317. int PASCAL NEAR lookup_color(sp)
  1318.  
  1319. char *sp;                /* name to look up */
  1320.     {
  1321.     register int i;        /* index into color list */
  1322.  
  1323.     /* test it against the colors we know */
  1324.     for (i = 0;  i < NCOLORS;  i++)
  1325.         {
  1326.         if (strcmp(sp, cname[i]) == 0)
  1327.             return (i);
  1328.         }
  1329.     return (-1);
  1330.     }
  1331.